package com.jinhongone.context.support;

import com.jinhongone.beans.MutablePropertyValue;
import com.jinhongone.beans.PropertyValue;
import com.jinhongone.beans.factory.config.BeanDefinition;
import com.jinhongone.beans.factory.support.BeanDefinitionRegistry;
import com.jinhongone.beans.factory.xml.XmlBeanDefinitionReader;
import com.jinhongone.context.utils.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author Administrator
 * @version 1.0
 * @description: ioc容器具体实现类，针对xml配置文件解析并创建ioc容器，初始化bean
 * @date 2025/4/26 10:33
 */
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {

    public ClassPathXmlApplicationContext(String configLocation) {
        //先赋值xml配置文件地址
        this.configLocation = configLocation;
        //再创建beanDefinition解析器
        beanDefinitionReader = new XmlBeanDefinitionReader();
        try {
            //调用刷新方法，解析xml配置文件并创建ioc容器，初始化bean.
            this.refresh();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public Object getBean(String beanName) throws Exception {
        //通过beanName通过容器获取bean对象
        Object bean = singletonObjects.get(beanName);
        if (bean != null) return bean;
        //容器中没有对象，通过注册表找到beanDefition,初始化bean并放置容器中
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinitionByName(beanName);
        if (beanDefinition == null) {
            return null;
        }
        //通过注册表中的全限定类型，使用反射创建bean对象
        String className = beanDefinition.getClassName();
        Class<?> clazz = Class.forName(className);
        Object beanInstance = clazz.newInstance();
        //处理bean中的成员变量
        MutablePropertyValue mutablePropertyValue = beanDefinition.getMutablePropertyValue();
        if (!mutablePropertyValue.isEmpty()) {
            for (PropertyValue propertyValue : mutablePropertyValue) {
                String name = propertyValue.getName(); //属性名称
                String ref = propertyValue.getRef(); //引用类型属性值
                String value = propertyValue.getValue(); //基本类型属性值
                //成员变量是引用数据类型时
                if (StringUtils.isNotEmpty(ref)) {
                    //获取propertyBean对象,此处使用方法递归实现
                    Object propertyBean = getBean(ref);
                    //属性赋值
                    setPropertyValue(name, clazz, beanInstance, propertyBean);
                }
                //成员变量是基本数据类型时
                if (StringUtils.isNotEmpty(value)) {
                    //赋值属性
                    setPropertyValue(name, clazz, beanInstance, value);
                }
            }
        }
        singletonObjects.put(beanName, beanInstance);
        return beanInstance;
    }

    private void setPropertyValue(String name, Class<?> clazz, Object invokeObj, Object propertyBean) throws InvocationTargetException, IllegalAccessException {
        //根据属性名获取set方法名
        String methodName = StringUtils.getSetMethodName(name);
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                //通过反射调用set方法进行复制操作
                method.invoke(invokeObj, propertyBean);
            }
        }
    }

    @Override
    public <T> T getBean(String beanName, Class<? extends T> clazz) throws Exception {
        //通过字节码文件.cast方法将Object类型转为class类型对象。
        return clazz.cast(getBean(beanName));
    }
}
